-- lua class定义

import "Scripts/base/define.lua";
import "Scripts/base/tableutil.lua";

function __is_kind_of(c,T)
	local __baseclass = getmetatable(c)
	while __baseclass do
		if __baseclass.__classname == T.__classname then
			return true
		end
		__baseclass = __baseclass.__baseclass
	end
	
	return false
end

function __is_class(c, T)
	return (c.__classname == T.__classname)
end

function class(name)
	local cls = {}
	cls.__classname = name
	
	cls.__tostring = function(c)
		return "Class of type "..c.__classname
	end

	cls.__newindex = function(t,k,v)
		retVal = false
		if t["__setvar"] ~= nil then
			retVal = t["__setvar"](t,k,v)
		end
		if retVal == false then
			rawset(t,k,v)
		end
	end

	cls.isKindOfClass = __is_kind_of
	cls.isClass = __is_class

	cls.__index = function(t,k)
		local prototype = rawget(t,"__prototype")
		if prototype ~= nil then
			ret = rawget(prototype,k)
			if ret ~= nil then return ret end
		end

		if k ~= "__index" and k ~= "__getvar" then
			if t["__getvar"] ~= nil then
				local ret = t["__getvar"](t,k)
				if ret ~= nil then return ret end
			end
			return rawget(t,k)
		end
	end

	_G[name] = setmetatable(cls, {
		 __call = function (c, ...)
		local instance = setmetatable({}, cls)
		instance.__prototype = cls
		if cls[name] then
			cls[name](instance, ...)
		end	
		return instance
	end})
	
	return function(superclass)
		if type(superclass) == 'table' then
			cls[superclass.__classname] = {}
			setmetatable(cls[superclass.__classname], superclass)
			for i,v in pairs(superclass) do
				if cls[i] == nil then
					cls[i] = v
				else
					cls[superclass.__classname][i] = v
				end
			end
			cls.__baseclass = superclass
		end
		
	end
end

-- 定义类的集合
AllClasses = {};
setmetatable(_G, AllClasses);
AllClasses.__index = AllClasses;

local AllClasses = AllClasses;


function haskey(t, k)
	if rawget(t, k) ~= nil then
		return true
	else
		return false
	end
end

-- 获得对象是否存在 k 函数
function hasfunction(t, k)
	local cur = t
	while cur do
		local func = rawget(cur, k)	
		if func and type(func) == "function" then
			return func
		end
		cur = getmetatable(cur)
	end

	return nil
end

-- 获得基类
local function getBase(t)
	if t.__base then
		return AllClasses[t.__base]
	else
		return nil
	end
end

-- 获得类型
local function getClass(t)
	if t.__name then
		return t.__name
	else
		return nil
	end
end


local function construct(tbClassType, tbObject, ...)

	print("+++11");
	print(tbClassType);
	print("+++");
	print(tbClassType.__base);
	if tbClassType.__base ~= "" then
		construct(AllClasses[tbClassType.__base], tbObject, ...)
	end

	local fnctor = rawget(tbClassType, "constructor");
	if fnctor then
		fnctor(tbObject, ...);			
	end
end

local function constructObject(tbClassType, ...)

	local tbNewObject = {}
	
	-- 对象实例的行为源于其类型
	setmetatable(tbNewObject, tbClassType)
	print("+++");
	print(tbClassType);
	print("+++");
	-- 构造在init函数里定义的属性
	construct(tbClassType, tbNewObject, ...)
	return tbNewObject
end

local function newindex(t, k, v)
	if not rawget(t,'__name') then
		local attribute = rawget(t, k)
		if not attribute then
			error("Can`t add key <" .. k.."> after Init")
		end	
	else 
		rawset(t,k,v)
	end
	
end

-- 实例化对象
local function newObject(tbClassType, ...)
	-- 设置新建属性时的__newindex不检测，使其能在init时增加额外的属性
	rawset(tbClassType, '__newindex', nil)

	local tbNewObject = constructObject(tbClassType, ...)
	
	-- 重定义新建属性时的__newindex，调用自己的newindex函数去重定向属性的存储位置和格式, 在Init后无该key则会报警
	-- (表t查阅自己 无k键值后新建 或 改变一个键值 时调用) 
	rawset(tbClassType, '__newindex', newindex)
	
	return tbNewObject
end

function DefineClass(className, baseName)
	local tb = {__name = className, __base = "", __class = className};

	if baseName then
		if type(baseName) == "string" then
			baseName = baseName;
		elseif type(baseName) == "table" then
			baseName = table.find(AllClasses, baseName);
		end

		tb.__base = baseName;
		setmetatable(tb, AllClasses[baseName]);
	else
		base = {
				__index = function (t, k)
					error("no key " .. k)
				end
		}

		setmetatable(tb, base);
	end

	rawset(tb, '__index', tb);
	rawset(tb, 'new', function(...) return newObject(tb, ...) end)
	rawset(tb, '__haskey', haskey)
	rawset(tb, '__hasfunction', hasfunction)
	rawset(tb, '__getBase', getBase)
	rawset(tb, '__getClass', getClass)
	
	AllClasses[className] = tb;

	return tb;
end